from twisted.internet import reactor, protocol
from ProtocolDefine import GameDefineProtocol
from TienLenUtils import *
from threading import Thread

class TienLenProtocol(protocol.Protocol):
    authenticated = False
    Username = None
    Status = None
    CurrentRoom = None
    PlayingStatus = None
    gamehandle = None
    RequestList = []
    ResponseList = []
     
    def connectionMade(self):
#        print self.transport.client
        self.gamehandle = UserAGame(self)
       
    def connectionLost(self,reason):
        if self.gamehandle.authenticated:
            self.factory.userQuit(self.gamehandle.username)        
        print "Lost connection ....",self.transport.client 
        
    def dataReceived(self, data):
        self.gamehandle.processData(data)        
        
    def response(self,data):
        #self.ResponseList.append(data)
        self.transport.write(data)
        self.transport.write("\n")
        
    def filterRequestData(self,data):
        if len(data)<=0:
            return False
        cmdlist = dir(GameDefineProtocol().GameCommand())
        args0 = data.strip().split(" ")[0]
        if args0 not in cmdlist:
            return False
        return True
        
    def processData(self,data):
        args = data.strip().split(" ")
        cmd = GameDefineProtocol()
        try:
            #unauthenticated command
            if args[0] == cmd.COMMAND_LOGIN:
                username = args[1]
                password = args[2]
                if self.authenticateUser(username, password):
                    self.authenticated = True
                    self.Username = username
                    self.response("Login successfully.")
                return
            if self.authenticated:
                #command use only when you are not in any room
                if not self.Status:
                    if args[0] == cmd.COMMAND_CREATE_ROOM:
                        self.factory.addRoom(self.Username)
                        self.response(self.Username+" has created a room.")
                        self.Status = "hosting"
                        self.CurrentRoom = self.Username
                        return
                    elif args[0] == cmd.COMMAND_JOIN:
                        roomname = args[1]
                        self.joinRoom(roomname)
                        self.Status = "joining"
                        self.CurrentRoom = roomname
                        return
                #command use only when you are in some room
                elif self.Status:
                    if args[0] == cmd.COMMAND_START:
                        if self.Status == "hosting":
                            self.startGame()
                        return
                    elif args[0] == cmd.COMMAND_READY:
                        if self.Status == "joining":
                            self.readyStatus()
                        return
                    elif args[0] == cmd.COMMAND_SHOW_PLAYERS:
                        if self.factory.RoomList[self.CurrentRoom]:
                            for u in self.factory.RoomList[self.CurrentRoom].userlist:
                                self.response(u)
                        return
                #all purpose command
                if args[0] == cmd.COMMAND_ECHO:
                    self.transport.write(data)
                    return
                elif args[0] == cmd.COMMAND_SHOW_ROOM:
                    for r in self.factory.RoomList.values():
                        self.response(r.host)
                    return
                elif args[0] == cmd.COMMAND_QUIT:
                    if self.Status == "hosting":
                        self.factory.userQuit(self.Username)       
                    self.response("Bye bye.")
                    self.transport.loseConnection()
                    return                
                else:
                    self.response("Unknown command "+args[0])
                    self.transport.loseConnection()
                    return
            #you can send command ony you are authenticated                 
            else:
                self.response("Your are not authenticated.")
                #self.transport.socket._sock.flush()
                self.transport.loseConnection()
                return                
        except Exception as ex:
            print "Error: ",ex         
        
    def authenticateUser(self,username,password):
        #test usage only
        bok = self.factory.addUser(username)
        if not bok:
            self.response("You're logging in.")
            return False
        else:        
            return True
        
    def joinRoom(self,roomname):
        bok = self.factory.joinRoom(self.Username,roomname)
        if not bok:
            self.response("Cant join room "+roomname)
        else:
            self.response(self.Username+" has joined room "+roomname)
        return
    
    def startGame(self):
        bok = self.factory.startRoom(self.Username)
        if not bok:
            self.response("Cant start room "+self.Username)
        else:
            self.response(self.Username+" has started a game.")
            
    def readyStatus(self):
        bok = self.factory.userReadyStatus(self.CurrentRoom,self.Username)
        if not bok:
            self.response("Cant ready. Problem...")
        else:
            self.response(self.Username+" has been ready.")
            

class TienLenFactory(protocol.ServerFactory):
    protocol = TienLenProtocol
    RoomList = []
    UserList = []
    UserStatusList = []
    UserRoomList = []
    
    def addUser(self,user):
        try:
            bfound = self.UserList.index(user)
        except:
            bfound = -1
        if bfound == -1:
            self.UserList.append(user)
            self.UserStatusList.append(None)
            self.UserRoomList.append(None)
            print user," has been added."
            return True            
        else:
            return False
            
    def createRoom(self,user,protocol):
        try:
            i = self.UserList.index(user)            
        except:
            i = -1            
        if i <> -1:
            if not self.UserStatusList[i]:
                room = AGame(user)
                room.join(user,protocol)
                self.RoomList.append(room)
                self.UserRoomList[i]= room
                self.UserStatusList[i] = "hosting"
                room.start()
    
    def partRoom(self,user):
        try:
            i = self.UserList.index(user)            
        except:
            i = -1            
        if i <> -1:
            room = self.UserRoomList[i]
            j = self.RoomList.index(room)
            self.RoomList[j].part(user)
            if self.RoomList[j].isEmpty():
                del self.RoomList[j]            
            self.UserRoomList[i] = None
            self.UserStatusList[i] = None
        
    def joinRoom(self,user,hostname,protocol):
        ifound = -1
        for i in range(0,len(self.RoomList)):
            if self.RoomList[i].host == hostname:
                ifound = i
                break
        if ifound <> -1:
            i = self.getUserIndex(user)
            if i <> -1:
                self.RoomList[ifound].join(user,protocol)
                self.UserRoomList[i] = self.RoomList[ifound]
                self.UserStatusList[i] = "joining"
        else:
            return False
        return True
    
    def startRoom(self,hostname):
        for room in self.RoomList:
            if room.status == "waiting" and room.host == hostname:
                room.startGame()
        return True
    
    def userReadyStatus(self,room,user):
        if self.RoomList.has_key(room):
            if self.RoomList[room].statusUser.has_key(user):
                self.RoomList[room].statusUser[user]=True
            else:
                return False
        else:
            return False
        return True
    
    def userQuit(self,user):
        try:
            i = self.UserList.index(user)
        except:
            i = -1
        if i <> -1:
            del self.UserList[i]
            del self.UserStatusList[i]
            del self.UserRoomList[i]
            
    def getUserStatus(self,user):
        try:
            i = self.UserList.index(user)
        except:
            i = -1
        if i <> -1:
            return self.UserStatusList[i]
        else:
            raise "Not found user"

    def getUserRoom(self,user):
        try:
            i = self.UserList.index(user)
        except:
            i = -1
        if i <> -1:
            return self.UserRoomList[i]
        else:
            raise "Not found user"
    
    def getUserIndex(self,user):
        try:
            i = self.UserList.index(user)            
        except:
            i = -1            
        return i
def main():
    """This runs the protocol on port 8000"""
    factory = TienLenFactory()    
    reactor.listenTCP(8000,factory)
    reactor.run()

# this only runs if the module was *not* imported
if __name__ == '__main__':
    main()
